const importFn = import.meta.glob('@/components/*/*.vue', { eager: true })
import message from './myMessage'
import type { App, DirectiveBinding } from 'vue'

declare module 'vue' {
  export interface ComponentCustomProperties {
    $message: typeof message
  }
}
interface comObj {
  default?: any
  [props: string]: any;
}

export default {
  async install(app: App) {
    // 自动导入
    for (const keys in importFn) {
      const component = (importFn[keys] as comObj).default
      app.component(component.__name, component)
    }

    // 定义指令
    defineDirective(app)
    // 定义一个原型函数
    app.config.globalProperties.$message = message
  }
}

const defineDirective = (app: App): void => {
  // 懒加载
  app.directive('lazy', {
    // 在绑定元素的 attribute 前
    // 或事件监听器应用前调用
    created(el, binding, vnode, prevVnode) { },
    // 在元素被插入到 DOM 前调用
    beforeMount(el, binding, vnode, prevVnode) { },
    // 在绑定元素的父组件
    // 及他自己的所有子节点都挂载完成后调用
    mounted(el: HTMLImageElement, binding: DirectiveBinding) {
      const observe = new IntersectionObserver(([{ isIntersecting }]) => {
        if (isIntersecting) {
          observe.unobserve(el)
          el.onerror = () => {
            el.src = ''
          }
          console.log(binding.value)
          el.src = binding.value
        }
      }, {
        threshold: 0
      })
      observe.observe(el)
    },
    // 绑定元素的父组件更新前调用
    beforeUpdate(el, binding, vnode, prevVnode) { },
    // 在绑定元素的父组件
    // 及他自己的所有子节点都更新后调用
    updated(el, binding, vnode, prevVnode) { },
    // 绑定元素的父组件卸载前调用
    beforeUnmount(el, binding, vnode, prevVnode) { },
    // 绑定元素的父组件卸载后调用
    unmounted(el, binding, vnode, prevVnode) { }
  })
  // 权限校验
  app.directive('permission', {
    created(el: HTMLElement, binding: DirectiveBinding) {
      const permission: string[] = ['1', '2', '3', '4'] // 假装这是从后台获取到的权限列表
      const hasPermission = binding.value.every((item: string) => permission.includes(item))
      if (!hasPermission) {
        el.style.display = 'none'
      }
    }
  })
  // 元素拖动
  app.directive('move', (el: HTMLElement, binding: DirectiveBinding) => {
    let moveElement: HTMLElement = el as HTMLElement
    const mousedown = (e: MouseEvent): void => {
      let X = e.clientX - el.offsetLeft
      let Y = e.clientY - el.offsetTop
      const move = (e: MouseEvent): void => {
        el.style.position = "fixed"
        el.style.left = e.clientX - X + 'px'
        el.style.top = e.clientY - Y + 'px'
      }
      document.addEventListener('mousemove', move)
      document.addEventListener("mouseup", () => {
        document.removeEventListener('mousemove', move)
      })
    }
    moveElement.addEventListener('mousedown', mousedown)
  })
}
